昨天在探討為什麼 Vite 在 dev server 的冷啟動這麼快時,目前我們只知道是因為有用上了瀏覽器的 native ESM 去省略打包的時間,但要做到這件事其實會需要處理蠻多問題,整個重點整理的話是利用以下幾點來實現:
光看文字可能沒那麼好懂,或許學習最快的方式就是動手做,千萬不要像我一樣前面講了八天的歷史故事光說不練。今天就實際來做實驗吧!
先附上今天做實驗的程式碼初始模板供參考。
$ mkdir esm-demo
$ cd esm-demo
$ pnpm init
$ pnpm add lodash-es
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ESM Demo</title>
</head>
<body>
<script type="module" src="main.js"></script>
</body>
</html>
import { has } from 'lodash-es';
console.log(has({ a: 1 }, 'a'));
此時如果你是 VS Code 的使用者,你可以安裝 Live Server 這個擴充套件,這是方便我們在本機直接 host 我們的網頁起來的工具,安裝後你可以對剛剛建立好的 index.html
去點右鍵並選擇「Open with Live Server」:
應該能自動打開瀏覽器畫面:
當你打開 dev tool 時,會看到 console 上印出這個錯誤:
Uncaught TypeError: Failed to resolve module specifier "lodash-es". Relative references must start with either "/", "./", or "../".
這是為什麼呢?這個錯誤訊息的意思是說無法解析到 lodash-es
這個檔案。當你想使用 native ESM 的寫法用 <script type=”module”>
的方式來載入你的 ESM 模組時,在載入模組時,瀏覽器需要絕對或相對路徑才能識別檔案,因此當你今天將上面 main.js
的引入路徑改成這樣就會正常了:
import { has } from './node_modules/lodash-es/lodash.js';
我們先記住這個結果,再來看另一個實驗。
光看文字可能很難懂,延續上一個實驗,其實基本上已經做完了,當你上一步最後的 main.js
的內容是這個樣子的時候:
import { has } from './node_modules/lodash-es/lodash.js';
console.log(has({ a: 1 }, 'a'));
我們這裡試著用 named import 的方式引入了 has
這個模組,當你這時用 Live Server 去將網頁啟起來後,打開 dev tool 後重整網頁,去觀察 network 中的 JS 載入數量:
你會看到一大串的 JS request 如瀑布一樣載進來,總共載了 600 多個,載入完成後 console 才印出 true
這個結果。
這是為什麼呢?如果你去看 node_modules/lodash-es/lodash.js 的這個檔案,會看到它是負責 export 其他子模組的主要入口檔。再追進去 has.js 這支檔案中,會看到裡面還引入了 _hasPath
,而其中又會如下圖一樣層層引入其他模組:
透過這個實驗可以發現,當今天是用 native ESM 的方式在瀏覽器上載入模組時,可能會因為用到的這個模組背後有上百、上千個依賴小模組而觸發過多的 request,造成頁面載入的卡頓,這反而會成為開發體驗上的另一個問題。而這也正是為何要做 dependency pre-bundling 的一個主因,一樣先記住這個結果,明天會再實際來看看 Vite 怎麼處理。
另外這邊有個有趣的發現,當你今天將 main.js
改成用 default import 直接載入 has
的話:
import has from './node_modules/lodash-es/has.js';
再去實驗看看 JS 模組的 request 數量,會從 600 多個降到剩下 60 多個,才知道原來原生的行為就算執行的檔案只有對其中的某一個模組做 named import,實際還是會去分析所有的模組依賴,看來 dev server 真的幫忙做了很多優化。
註:第二個實驗範例是參考高見龍在這個影片 demo 的靈感,選擇用
has
這個模組看起來就是為了感受一下大型依賴的感覺。
今天我們實際用 lodash-es
純手工實驗了下要在 native ESM 的瀏覽器環境下載入第三方套件可能會遇到什麼問題,明天我們將繼續來做相關的實驗,最後再統一做 Vite 實現原理的重點說明!